package security.crypto;

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import security.crypto.aes.AES;
import utils.Base64Processing;

/**
 * The Class StringEncryption is responsible to cipher and decipher it abstracting from all the processing
 * needed to do that.
 */
public class SimmEncryption{

	public static Key generateKeyFromPassHash(String passHash){	
		try{
			char[] passwordChar = passHash.toCharArray();
			
			byte[] salt = new byte[] { 0x7d, 0x60, 0x43, 0x5f, 0x02, (byte) 0xe9, (byte) 0xe0, (byte) 0xae};
			int iterationCount = 2048;
			PBEKeySpec pbeSpec = new PBEKeySpec(passwordChar, salt, iterationCount);
			SecretKeyFactory keyFact = SecretKeyFactory.getInstance("PBEWithSHA256And128BitAES-CBC-BC");

			Key key = keyFact.generateSecret(pbeSpec);

			return new SecretKeySpec(key.getEncoded(), "AES");
		}catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * Generate a random key to be used to cipher something using AES encryption algorithm.
	 * 
	 * @return the key
	 * 
	 */
	public static SecretKey generateKey(){
		KeyGenerator generator;
		try {
			generator = KeyGenerator.getInstance("AES");
			generator.init(128);

			return generator.generateKey();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * Given a text to cipher and the key that will be used to cipher the text cipher it and returns a
	 * string in base64 representation.
	 * 
	 * @param input the text that will be ciphered.
	 * @param key the key to be used to cipher the text.
	 * 
	 * @return the string
	 */
	public static String cipherString(String input, Key key) {

		String cipherString = null;

		try{
			byte[] plainText = input.getBytes("UTF-8");
			if(plainText.length!=0){
				AES aes = new AES();
				aes.init(false, 1, key.getEncoded());
				byte[] cipherText = aes.doFinal(plainText);	
				
				cipherString = Base64Processing.encodeData(cipherText);				
			}
		}catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return cipherString;		
	}

	/**
	 * Given a previously ciphered string and the key that had been used to cipher it, makes the backward
	 * operation and returns the original text to the application.
	 * 
	 * @param cipherInput the text to be deciphered.
	 * @param key the key that will be used to decipher it.
	 * 
	 * @return the original text before being ciphered.
	 */
	public static String decipherString(String cipherInput, Key key){

		String decipherString = null;

		try{
			byte[] cipherText = Base64Processing.decodeData(cipherInput);
			if(cipherText.length!=0){
				AES aes = new AES();
				aes.init(true, 1, key.getEncoded());
				byte[] decipherText = aes.doFinal(cipherText);
				
				decipherString = new String(decipherText, "UTF-8");
			}
		}catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		return decipherString;		
	}
}